Loading packages

library(cowplot)
library(ggplot2)
source('spatstat_vectra.R')

plot_function <- function(csd, ctypes) {
    plt <- ggplot() + theme_bw() + 
           geom_point(data = csd[grep('Other', csd$Phenotype),],
               aes(x=x, y=y), col = '#b5b3ae', size=2.5) +
        geom_point(data = csd[csd$Phenotype%in%c('PAX5+PDL1-','PAX5+PDL1+'),],
               aes(x=x, y=y), col = '#fc8105', size=2.5) +
           geom_point(data = csd[grep('PAX5+PDL1+', csd$Phenotype, fixed=T),],
               aes(x=x, y=y), col = '#fff761', size=0.01, shape=1, stroke=1) + 
           geom_point(data = csd[grep('CD3+CD8-',csd$Phenotype, fixed=T),],
               aes(x=x, y=y), col = '#34c9eb', size=2.5) +
           geom_point(data = csd[grep('CD3+CD8+',csd$Phenotype, fixed=T),],
               aes(x=x, y=y), col = '#4634eb', size=2.5) +
            geom_point(data = csd[grep('PD1+', csd$Phenotype, fixed=T),],
               aes(x=x, y=y), col = '#fff761', size=0.01,shape=1, stroke=1) + 
           geom_point(data = csd[grep('CD163', csd$Phenotype),],
               aes(x=x, y=y), col = '#a834eb', size=2.5) +
           geom_point(data = csd[grep('CD163+PDL1+', csd$Phenotype, fixed=T),],
               aes(x=x, y=y), col = '#fff761', size=0.01, shape=1, stroke=1) 
    return(plt +theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
                   panel.background = element_blank()))
}

Example images (5 images)

images = c(
    'exported_mIF/HO105-003_[11564,35679]_cell_seg_data.txt',
    'exported_mIF/HO105-003_[11564,35679]_cell_seg_data.txt',
    'exported_mIF/HO105-025_[9621,46812]_cell_seg_data.txt',
    'exported_mIF/HO105-182_[8076,47954]_cell_seg_data.txt',
    'exported_mIF/HO105-020_[9758,38701]_cell_seg_data.txt'
)

ctypepairs = list(
    c('CD3+CD8-PD1-', 'CD8+CD8-PD1+', 'CD3+CD8+PD1-', 'CD3+CD8+PD1+'),
    c('CD163+PDL1-', 'CD163+PDL1+', 'CD3+CD8+PD1-', 'CD3+CD8+PD1+'),
    c('CD163+PDL1-', 'CD163+PDL1+'),
    c('CD163+PDL1-', 'CD163+PDL1+'),
    c('CD163+PDL1-', 'CD163+PDL1+')
                  )


XposCol = 'Cell X Position'
YposCol = 'Cell Y Position'
PhenoCol = 'Phenotype'

#i=1
for (i in 1:length(images)) {
    plist = list()
    Table <- purrr::map_df(images[i], read_cell_seg_data, 
                       pixels_per_micron = "auto", remove_units=FALSE)

    # replace empty phenotype with "Other"
    Table$Phenotype[Table$Phenotype == ""] = "Other"
  
    # define csd for ppp
    csd <- as.data.frame(Table[, c(PhenoCol, XposCol, YposCol)])
    colnames(csd) = c('Phenotype', 'x',  'y')

    plt1 <- local({

        plt1 = plot_function(csd, c('Tumor', 'Tcell', 'Macrophage', 'Other'))
        #plt <- plt + ggtitle(images[i]) 
        plt1 <- plt1 + #ggtitle(images[i]) + 
          theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
                axis.title.x=element_blank(), axis.text.x=element_blank(),
                axis.ticks.x=element_blank(), axis.title.y=element_blank(), 
                axis.text.y=element_blank(), axis.ticks.y=element_blank(),
                panel.background = element_blank()) + ggtitle('all cell types')# + scale_y_reverse()
        return(plt1)
    })

    #print(plt1)    
    xlims <- layer_scales(plt1)$x$get_limits()
    ylims <- layer_scales(plt1)$y$get_limits()

    csd2 <- csd
    plt2 <- plot_function(csd2[csd2$Phenotype%in%ctypepairs[[i]],], 
                         c('Tumor', 'Tcell', 'Macrophage', 'Other')) + 
           xlim(xlims) + ylim(ylims)# + scale_y_reverse()
    plt2 <- plt2 + 
          theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
                axis.title.x=element_blank(), axis.text.x=element_blank(),
                axis.ticks.x=element_blank(), axis.title.y=element_blank(), 
                axis.text.y=element_blank(), axis.ticks.y=element_blank(),
                panel.background = element_blank()) + 
           ggtitle(paste0('focus: ', paste0(ctypepairs[[i]], collapse='/')))# + scale_y_reverse() 

    plot_row <- plot_grid(plt1, plt2)

    title <- ggdraw() +
        draw_label(
                   images[i],
                   fontface = 'bold',
                   x = 0,
                   hjust = 0
                   ) +
           theme(
                 plot.margin = margin(0,0,0,7)
                 )
    
    print(plot_grid(title, plot_row, ncol=1, rel_heights = c(0.1,1)))
}

## Reading cell seg data with comma separator.

Visualization of the images

phenotype_complete = c("CD163+PDL1-","CD163+PDL1+",
                       "CD3+CD8-PD1-", "CD3+CD8-PD1+", "CD3+CD8+PD1-", "CD3+CD8+PD1+",
                       "Other","Other PDL1+", "PAX5+PDL1-", "PAX5+PDL1+", "")

color_complete = list("magenta", "brown",
                   "red", "blue", "green", "yellow",
                   "gray", "pink", "orange", "cyan", "gray")
names(color_complete) = phenotype_complete

fig.prefix.complete = './complete'
selected_spatstat_statistics = c('K', 'L') 
# can be any subset of ('K', 'Kdot', 'L', 'Ldot', 'F', 'J', 'G', 'Gdot', 'pcf')
r_vec = c(5, 10, 25, 50, 75, 100)

plotter_sample = T
plotter_quadrat = T
plotter_alltypes = T

plotter = list(plotter_sample, plotter_quadrat, plotter_alltypes)

outputs_complete = list()
for (file in images){
    cat('processing', file)
  
  samplename = gsub('_cell_seg_data.txt', '', tail(strsplit(file, '/')[[1]],1))
  outputs_complete[[samplename]] = do_analyse(seg_path = file, PhenoOrder = phenotype_complete, 
                                          ColsOrder = color_complete, XposCol = 'Cell X Position', 
                                          YposCol = 'Cell Y Position', PhenoCol = 'Phenotype',
                      sample_name = samplename, plotter = plotter, fig.prefix = fig.prefix.complete,
                      r_vec = r_vec, spatstat_statistics = selected_spatstat_statistics)
}
## processing exported_mIF/HO105-003_[11564,35679]_cell_seg_data.txtdimensions of the data with distances is  2638  times  210
##        Other   PAX5+PDL1- CD3+CD8-PD1-  CD163+PDL1- CD3+CD8+PD1- CD3+CD8-PD1+ CD3+CD8+PD1+ 
##          488         1240          586          216           95           11            2
## computing K of alltypes
## Computing limits
## interpolating K
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## computing L of alltypes
## Computing limits
## interpolating L
## significance band width is 0, instead normalizing by width_eps = 10^(-5).
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## processing exported_mIF/HO105-003_[11564,35679]_cell_seg_data.txtdimensions of the data with distances is  2638  times  210
##        Other   PAX5+PDL1- CD3+CD8-PD1-  CD163+PDL1- CD3+CD8+PD1- CD3+CD8-PD1+ CD3+CD8+PD1+ 
##          488         1240          586          216           95           11            2
## computing K of alltypes
## Computing limits
## interpolating K
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## computing L of alltypes
## Computing limits
## interpolating L
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## processing exported_mIF/HO105-025_[9621,46812]_cell_seg_data.txtdimensions of the data with distances is  1833  times  214
##        Other   PAX5+PDL1-  CD163+PDL1+ CD3+CD8-PD1-  Other PDL1+ CD3+CD8+PD1+ CD3+CD8+PD1- CD3+CD8-PD1+  CD163+PDL1- 
##          533          569          566           50           79            1           24           10            1
## computing K of alltypes
## Computing limits
## interpolating K
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## significance band width is 0, instead normalizing by width_eps = 10^(-5).
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## significance band width is 0, instead normalizing by width_eps = 10^(-5).
## significance band width is 0, instead normalizing by width_eps = 10^(-5).
## significance band width is 0, instead normalizing by width_eps = 10^(-5).
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## significance band width is 0, instead normalizing by width_eps = 10^(-5).
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## computing L of alltypes
## Computing limits
## interpolating L
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## significance band width is 0, instead normalizing by width_eps = 10^(-5).
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## significance band width is 0, instead normalizing by width_eps = 10^(-5).
## significance band width is 0, instead normalizing by width_eps = 10^(-5).
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## significance band width is 0, instead normalizing by width_eps = 10^(-5).
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## processing exported_mIF/HO105-182_[8076,47954]_cell_seg_data.txtdimensions of the data with distances is  1151  times  212
##   PAX5+PDL1+   PAX5+PDL1-  CD163+PDL1+ CD3+CD8+PD1-        Other  CD163+PDL1- CD3+CD8-PD1+ CD3+CD8-PD1- 
##           90          643          105           48          108          126            2           29
## computing K of alltypes
## Computing limits
## interpolating K
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## computing L of alltypes
## Computing limits
## interpolating L
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## NA in calculating significance bands so width significance band is infinit, normalized statistic set to 0.
## processing exported_mIF/HO105-020_[9758,38701]_cell_seg_data.txtdimensions of the data with distances is  1362  times  210
##        Other  CD163+PDL1+   PAX5+PDL1- CD3+CD8-PD1+ CD3+CD8-PD1-  CD163+PDL1-   PAX5+PDL1+ 
##           65          144         1002            9           84           57            1
## computing K of alltypes
## Computing limits
## interpolating K
## significance band width is 0, instead normalizing by width_eps = 10^(-5).
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## computing L of alltypes
## Computing limits
## interpolating L
## significance band width is 0, instead normalizing by width_eps = 10^(-5).
## significance band width is 0, instead normalizing by width_eps = 10^(-5).
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA
## NA or NaN 'obs': too few counts in observed pattern to compute centered and normalized statistic, both set to NA

The script do_analyse measures multiple statistics (K and L statistics were chosen in the example above) for the given image (seg_path). Apart from the statistics itself, it will save images at the location specified by fig.prefix. One example image (K statistics) of all pairs of cell types considered (defined by PhenoOrder) is shown below. Note that + and - signs are converted to T and F. The red line and gray shadow indicate theoretical statistics when the pair of cell types have no geometric association. The solid black line represents the actual statistic.

Example image

Creating a feature matrix

Feature matrix can be created with feature_extract function.

mat = feature_extract(outputs_complete)
## begin feature extraction
## end feature extraction
df = data.frame(feature = colnames(mat), stringsAsFactors=F)

# some features are excluded in the study
keyword_exclude = c('counts_sample', 'counts_lognormed', 'counts_pairwise', 'counts_pairwise', 
        'density_lognormed', 'density_lognormed', 'Ldot_', 'Kdot_', 'pcf_')

df$Use = rep(TRUE, ncol(mat))

for (key in keyword_exclude) {
    df$Use[grep(key, colnames(mat))] = FALSE
}

# unnormalized spatial features were also excluded
ind_unnormalized = setdiff(grep('radius', df$feature), grep('Normalized', df$feature))
df[ind_unnormalized, 'Use'] = FALSE



# feature annotation

df$celltype = unlist(lapply(df$feature, function(x) tail(strsplit(x, '_', fixed=T)[[1]],1)))
df$celltype = unlist(lapply(df$celltype,
                    function(x) paste0(sort(strsplit(x, '/')[[1]]), collapse='/')
                    ))

feat_key = c(count='counts_[a-z]+', density='density_', Xstat='X2stat_[a-z]', MedianDistance='MED|distance_ratio',
        RelDistance = 'Relative_distance', MADDistance='MAD', Fstat='F_radius', Gstat='G_radius|Gdot_radius', 
        Kstat='K_radius|Kdot_radius', Lstat='L_radius|Ldot_radius', PCFstat='pcf_radius')


ctype_key = grep('counts_sample', df$feature, value=T)
ctype_key = unlist(lapply(ctype_key, function(x) tail(strsplit(x, '_', fixed=T)[[1]], 1)))

df$feat_group = NA
for (i in 1:length(feat_key)) {
    df$feat_group[grep(feat_key[i], df$feature)] = names(feat_key)[i] 
}
for (i in 1:length(ctype_key)) {
    df[[ctype_key[i]]] = FALSE
    df[[ctype_key[i]]][grep(ctype_key[i], df$feature, fixed=T)] = TRUE
    for (overlap in setdiff(grep(ctype_key[i], ctype_key, value=T, fixed=T), ctype_key[i])) {
        df[[ctype_key[i]]][grep(overlap, df$feature, fixed=T)] = FALSE
    }
}

for (radius in c(5,10, 25, 50, 75, 100, 150, 200, 250, 500)) {
    ind = grep(paste0('radius ', as.character(radius), '_'), df$feature)
    df$feat_group[ind] = paste0(df$feat_group[ind], ', r=', as.character(radius))
}
#

Feature overview

color = c(
          "NonSpatial" = "#72ac5c",
          "GlobalSpatial" = "#7f64b9",
          "LocalSpatial" = "#bb7438",
          "Poisson, r_5" = "#c2215f",
          "Poisson, r_10" = "#c76f90",
          "Poisson, r_25" = "#da9eb4",
          "Poisson, r_50" = "#e2b2c3",
          "Poisson, r_75" = "#f2dee5",
          "Poisson, r_100" = "#f7ecf0",
          "Poisson, local" = "#c2215f",
          "Poisson, global" = "#e2b2c3"
          )


freq = data.frame(table(df[df$Use, ]$feat_group))

ftypes = list(
    NonSpatial=c("count", "density"),
    GlobalSpatial=c("MAD_Distance", "Median_Distance", 'Xstat'),
    LocalSpatial=c("MAD_Min_Distance", "Median_Min_Distance", "RelDistance")
    )
radius = list(local=c(5, 10, 25), global=c(50, 75, 100)) 

for (r in 1:length(radius)) {
    feats = c()
    for (rs in radius[[r]]) {
        feats = c(feats, grep(paste0('r=', as.character(rs), '$'), df$feat_group, value=T))
    }
    ftypes[[paste0('Poisson, ',names(radius)[r])]] = unique(feats)
}

freq$category = NA
for (i in 1:length(ftypes)){
    freq$category[freq$Var1%in%ftypes[[i]]] = names(ftypes)[i]
}

freq$category = factor(freq$category, levels =names(ftypes))
freq$Feat = unlist(lapply(freq$Var1, function(x) strsplit(as.character(x), ',')[[1]][1]))
freq$Feat = gsub('_', ' ', freq$Feat, fixed=T)
freq$Var1 = factor(freq$Var1, levels=freq$Var1[order(freq$category)])
freq$Feat = factor(freq$Feat, levels=unique(freq$Feat[order(freq$category)]))
ggplot(freq[!is.na(freq$category),], aes(x=Feat, y=Freq, fill=category)) + geom_bar(stat='identity') + theme_bw() +
    theme(axis.text.x = element_text(angle=90, vjust=1, hjust=1)) + scale_fill_manual(values=color) + 
    xlab("Feature type") + ylab("# of features")

Session Information

sessionInfo()
## R version 4.0.0 (2020-04-24)
## Platform: x86_64-conda_cos6-linux-gnu (64-bit)
## Running under: CentOS Linux 7 (Core)
## 
## Matrix products: default
## BLAS/LAPACK: /home/y.kim1/anaconda2/envs/Vectra/lib/libopenblasp-r0.3.12.so
## 
## locale:
##  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8     LC_MONETARY=fr_FR.UTF-8    LC_MESSAGES=en_US.UTF-8    LC_PAPER=fr_FR.UTF-8      
##  [8] LC_NAME=C                  LC_ADDRESS=C               LC_TELEPHONE=C             LC_MEASUREMENT=fr_FR.UTF-8 LC_IDENTIFICATION=C       
## 
## attached base packages:
## [1] grid      stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] VIM_6.2.2              colorspace_2.1-0       Rtsne_0.16             survminer_0.4.9        ggpubr_0.2.5           magrittr_2.0.3         readxl_1.4.2           sp_1.5-0              
##  [9] latex2exp_0.9.5        reshape2_1.4.4         RColorBrewer_1.1-3     phenoptr_0.3.2         tiff_0.1-11            remotes_2.4.2          spdep_1.2-8            sf_0.9-5              
## [17] spData_2.2.0           spatstat_3.0-3         spatstat.linnet_3.0-6  spatstat.model_3.2-1   rpart_4.1.16           spatstat.explore_3.1-0 nlme_3.1-150           spatstat.random_3.1-4 
## [25] spatstat.geom_3.1-0    spatstat.data_3.0-1    forcats_1.0.0          stringr_1.5.0          dplyr_1.1.1            purrr_1.0.1            readr_2.1.4            tidyr_1.3.0           
## [33] tibble_3.2.1           tidyverse_1.3.2        ggplot2_3.4.1          cowplot_1.1.1          rmarkdown_2.21         nvimcom_0.9-102       
## 
## loaded via a namespace (and not attached):
##   [1] backports_1.4.1       plyr_1.8.7            splines_4.0.0         digest_0.6.31         foreach_1.5.2         htmltools_0.5.5       fansi_1.0.4           tensor_1.5           
##   [9] googlesheets4_1.0.1   tzdb_0.3.0            modelr_0.1.11         vroom_1.6.1           timechange_0.2.0      spatstat.sparse_3.0-1 rvest_1.0.3           haven_2.5.2          
##  [17] xfun_0.38             crayon_1.5.2          jsonlite_1.8.4        survival_3.4-0        zoo_1.8-11            iterators_1.0.14      glue_1.6.2            polyclip_1.10-4      
##  [25] gtable_0.3.3          gargle_1.2.1          car_3.1-0             DEoptimR_1.0-11       abind_1.4-5           scales_1.2.1          DBI_1.1.3             Rcpp_1.0.9           
##  [33] laeken_0.5.2          xtable_1.8-4          units_0.8-0           bit_4.0.5             proxy_0.4-27          km.ci_0.5-6           vcd_1.4-10            httr_1.4.4           
##  [41] wk_0.6.0              pkgconfig_2.0.3       farver_2.1.1          nnet_7.3-17           sass_0.4.5            dbplyr_2.3.2          deldir_1.0-6          utf8_1.2.3           
##  [49] tidyselect_1.2.0      labeling_0.4.2        rlang_1.1.0           munsell_0.5.0         cellranger_1.1.0      tools_4.0.0           cachem_1.0.6          cli_3.6.1            
##  [57] generics_0.1.3        ranger_0.14.1         broom_1.0.4           evaluate_0.20         fastmap_1.1.1         yaml_2.3.7            goftest_1.2-3         knitr_1.42           
##  [65] bit64_4.0.5           fs_1.6.1              robustbase_0.93-6     survMisc_0.5.6        s2_1.1.0              xml2_1.3.3            compiler_4.0.0        e1071_1.7-11         
##  [73] ggsignif_0.6.3        spatstat.utils_3.0-2  reprex_2.0.2          bslib_0.4.2           stringi_1.7.12        highr_0.10            lattice_0.20-45       Matrix_1.4-1         
##  [81] classInt_0.4-3        KMsurv_0.1-5          vctrs_0.6.1           pillar_1.9.0          lifecycle_1.0.3       lmtest_0.9-38         jquerylib_0.1.4       data.table_1.14.2    
##  [89] R6_2.5.1              KernSmooth_2.23-18    gridExtra_2.3         codetools_0.2-18      boot_1.3-28           MASS_7.3-58.1         withr_2.5.0           mgcv_1.8-40          
##  [97] parallel_4.0.0        hms_1.1.3             class_7.3-20          carData_3.0-5         googledrive_2.0.0     lubridate_1.9.2